/* 
  接口：相当于一种数据类型规范 用来保证数据通信的规范性、统一性

  可选参数 age?:number 表示 age 这个参数可有可无

  只读属性：readonly age:number 固定属性值 不允许修改

  属性检查：[property:type]:type 要求属性名是某种类型，其值也是某种类型 
  但是不能违反其他属性的规则 不然属性值类型可能会前后矛盾

  解决方法：[property:type]:any

    好处：对可能存在的属性进行预定义，还可以避免引用不存在属性时候的报错
*/

// 定义一个接口
interface UserCheck {
  name: string;
  age: number;
  sex?: string;
}

// 调用接口
function checkUser(user: UserCheck) {
  console.log(user);
}

// 参数类型检查严格按照接口的标准 不能多 不能少 顺序可乱
checkUser({ name: "木杉", age: 20, sex: "男" });

interface Point {
  readonly x: number;
  readonly y: number;
}

let point: Point = { x: 10, y: 20 };
// point.x = 5; 无法更改属性值
console.log(point);

interface Square {
  width: number;
  color: string;
  bdr?: number;
  readonly logo?: "mS";
  [other: string]: any; // 允许添加自定义属性
}

let square: Square = {
  width: 10,
  color: "#000",
  bdr: 10,
  logo: "mS",
  logoColor: "red",
};

console.log(square);

// 函数接口定义
interface fnCheck{
  (s:string, n:number,...args):string
}

let fn: fnCheck = function (a,b,...rest) {
  return a + b + rest.reduce((total,index) => total + index);
}

// 属性检测接口
interface propCheck {
  [index: string]: string;
  readonly  [index: number]: string; // 属性必须是字符串的类型或者是字符串的子类型 string undefined null...
}

let objTest: propCheck = {
  "name": "哈哈",
  9527: "111",
  age: "20"
}

// 对类的检查一般是检查其中的属性或者方法 但是不能检测 constructor
interface classCheck {
  getDate(): string
  nowDate: Date
}

// 类需要实现这个接口 并且实现接口中所有的属性和方法
class Test implements classCheck { 
  nowDate = new Date();

  constructor() {
    
  }

  getDate() {
    return this.nowDate.toLocaleString();
  }
}

// 接口的继承 接口支持多继承
interface Father{
  fatherName: string;
}
interface Mother {
  momName: string;
}
interface Son extends Father, Mother{
  sonName: string;
}
let sonObje:Son = {
  fatherName: "John",
  momName: "mary",
  sonName: "Bob"
}

